const PENDIND = "pending";
const REJECTED = "rejected";
const FULFILLED = "fulfilled";

class MyPromise {

    #state = PENDIND;
    #result = null;
    #handlers = [];

    constructor(callback) {

        /**
         * 在构造函数中创建reslove和reject可以保证函数运行时函数内this指向MyPromise实例
         */
        const resolve = (data) => {
            this.#changeState(FULFILLED, data);
        }
        const reject = (reason) => {
            this.#changeState(REJECTED, reason);
        }

        // 调用函数
        callback(resolve, reject);
    }

    #changeState(state, result) {
        if (this.#state !== PENDIND) return;
        this.#state = state;
        this.#result = result;

        this.#run();
    }

    static #isPromiseLike(data) {
        return data && typeof data.then === "function";
    }

    static #runMicroTask(func) {
        setTimeout(func, 0);
    }

    #runOne(callback, resolve, reject) {
        MyPromise.#runMicroTask(() => {
            if (typeof callback !== "function") {
                const settled = this.#state === FULFILLED ? resolve : reject;
                settled(this.#result);
                return;
            }
            try {
                const data = callback(this.#result);
                if (MyPromise.#isPromiseLike(data)) {
                    data.then(resolve, reject);
                } else {
                    resolve(data);
                }
            } catch (e) {
                reject(e);
            }
        });
    }

    #run() {
        if (this.#state === PENDIND) return;
        
        while (this.#handlers.length) {
            const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift();
            if (this.#state === FULFILLED) {
                this.#runOne(onFulfilled, resolve, reject);
            } else {
                this.#runOne(onRejected, resolve, reject);
            }
        }
    }

    // 返回一个Promise，是方法可以链式调用
    then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
            this.#handlers.push({
                onFulfilled,
                onRejected,
                resolve,
                reject
            });

            // 保证正常调用
            this.#run();
        });
    }

    static all(promiseList) {
        return new MyPromise((resolve, reject) => {
            let t = promiseList.length;
            let result = new Array(t);
            const isOk = () => {
                t = t - 1;
                if (t <= 0) {
                    resolve(result);
                }
            }
            for (const [i, pro] of promiseList.entries()) {
                if (MyPromise.#isPromiseLike(pro)) {
                    pro.then((data) => {
                        result[i] = data;
                        isOk();
                    }, reject);
                } else {
                    result[i] = pro;
                    isOk();
                }
            }
        });
    }
}

// MyPromise 测试
const my = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve("你好")
        reject("好不好")
    }, 1000);
});
my.then((data) => {
    console.log(data)
    return new Promise((resolve) => {
        resolve("你好 +1");
    });
}).then((data) => {
    console.log(data)
    return data + (times++);
});

// MyPromise.all 测试
const promise1 = 111;
const promise2 = new MyPromise((resolve) => resolve(222));
const promise3 = Promise.resolve(333);
const promise4 = Promise.reject(4444);
// MyPromise.all([promise1, promise2, promise3])
MyPromise.all([promise1, promise2, promise3, promise4])
    .then((result) => {
        console.log("MyPromise.all result: ", result);
    }, (err) => {
        console.log("MyPromise.all error: ", err);
    })